package com.hanxiaozhang.jdk8;

import com.hanxiaozhang.commomentity.Person;
import com.hanxiaozhang.commomentity.Student;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 〈一句话功能简述〉<br>
 * 〈流-相关使用方法总结〉
 *
 * @author hanxinghua
 * @create 2022/9/28
 * @since 1.0.0
 */
public class No8Stream {

    public static void main(String[] args) {


        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        list.add(8);
        list.add(9);
        list.add(10);
        list.add(11);

        // 1. removeIf()的使用
        System.out.println("---- 1. removeIf()的使用");
        list.removeIf(i -> i % 2 == 0);
        System.out.println(list);


        // 2. debug 关于Stream高级测试功能的演示例子
        System.out.println("---- 2. debug 关于Stream高级测试功能的演示例子");
        List<Integer> list1 = list.stream()
                .skip(1)
                .limit(6)
                .filter(x -> x % 2 == 0)
                .collect(Collectors.toList());
        System.out.println(list1.size());


        // 3. allMatch() 与 anyMatch() 的区别：
        System.out.println("---- 3. allMatch() 与 anyMatch() 的区别");
        // allMatch: 判断条件是否匹配所有元素
        System.out.println(list.stream().allMatch(x -> {
            return (x % 2) == 1;
        }));

        // anyMatch：判断条件至少匹配一个元素
        System.out.println(list.stream().anyMatch(x -> {
            return (x % 3) == 1;
        }));


        // 4. findFirst() 与 findAny()的区别：
        System.out.println("---- 4. findFirst() 与 findAny()的区别");
        // findFirst：获取流中的第一个元素
        System.out.println(list.stream().findFirst().get());

        // findAny：获取流中任意一个，存在随机性
        System.out.println(list.stream().findAny().get());


        // 5. 按list集合中的某个属性分组，并且分组后，map有序
        System.out.println("---- 5. 按list集合中的某个属性分组，并且分组后，map有序");
        List<Student> studentList = new ArrayList();
        studentList.add(new Student("1", "男1"));
        studentList.add(new Student("2", "女"));
        studentList.add(new Student("3", "女"));
        studentList.add(new Student("4", "男2"));
        studentList.add(new Student("5", "男1"));
        studentList.add(new Student("6", "女"));
        studentList.add(new Student("6", "男1"));
        LinkedHashMap<String, List<Student>> map =
                studentList.stream().collect
                        (Collectors.groupingBy(Student::getSex,
                                LinkedHashMap::new, Collectors.toList()));
        System.out.println(map);


        // 6. peek() 与 map() 的分别：
        System.out.println("---- 6. peek() 与 map() 的分别");
        // peek：接收一个没有返回值的λ表达式，可以做一些输出，外部处理等。
        // Tips: peek()后边必须跟其他方法，否则不执行。

        studentList.stream().peek(
                x -> {
                    if (x.getSex().contains("男")) {
                        x.setAddress("顺义");
                    } else {
                        x.setAddress("朝阳");
                    }
                }).collect(Collectors.toList());
        System.out.println(studentList);

        // map：接收一个有返回值的λ表达式，之后Stream的泛型类型将转换为map参数λ表达式返回的类型
        List<String> maleIds = studentList.stream().map(x -> {
            if (x.getSex().contains("男")) {
                return x.getId();
            } else {
                return null;
            }
        }).filter(x -> x != null).collect(Collectors.toList());
        System.out.println(maleIds);


        // 7. list 转 map
        List<Person> personList1 = new ArrayList<>();
        personList1.add(new Person("1001", "张三"));
        personList1.add(new Person("1002", "李四"));
        // 写法一：
        Map<String, Person> personMap1 = personList1.stream().collect(Collectors.toMap(Person::getPersonNo, Function.identity()));
        System.out.println("list2map" + personMap1);
        // 写法二：
        Map<String, Person> personMap2 = personList1.stream().collect(Collectors.toMap(p -> p.getPersonNo(), p -> p));
        System.out.println("list2map" + personMap2);

        // 问题1：原list有重复的key
        List<Person> personList2 = new ArrayList<>();
        // 小A和小B key重复
        personList2.add(new Person("1001", "小A"));
        personList2.add(new Person("1001", "小B"));
        personList2.add(new Person("1001", "小D"));
        personList2.add(new Person("1003", "小C"));

        // key 重复, 没有处理 value 的策略, 异常 java.lang.IllegalStateException: Duplicate key 小A
        // Map<String, String> no2NameMap = personList2.stream().collect(Collectors.toMap(Person::getPersonNo, Person::getName));

        // 问题1-策略一：用后面的value 覆盖前面的value
        Map<String, String> no2NameMap1 = personList2.stream()
                .collect(Collectors.toMap(Person::getPersonNo, Person::getName, (v1, v2) -> v2));
        //{1003=小C, 1001=小D};
        System.out.println("keyDuplicate: " + no2NameMap1);

        // 问题1-策略二：将前面的value 和后面的value拼接起来
        Map<String, String> no2NameMap2 = personList2.stream()
                .collect(Collectors.toMap(Person::getPersonNo, Person::getName, (v1, v2) -> v1 + "，" + v2));
        //{1003=小C, 1001=小A，小B，小D}
        System.out.println("keyDuplicate2: " + no2NameMap2);

        // 问题1-策略三：将重复key的数据组成集合
        Map<String, List<String>> no2NameListMap3 = personList2.stream().collect(Collectors.toMap(Person::getPersonNo
                , person -> {
                    List<String> personNameList = new ArrayList<>();
                    personNameList.add(person.getName());
                    return personNameList;
                }, (v1, v2) -> {
                    v1.addAll(v2);
                    return v1;
                }));
        // {1003=[小C], 1001=[小A, 小B, 小D]}
        System.out.println("keyDuplicate3: " + no2NameListMap3);


    }


    /**
     * java8 新特性流
     *
     * @param personList 原list
     */
    private void stream2map(List<Person> personList) {

    }


}
